﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using Core.DeviceProtocol;
using Core.Helper;
using log4net;

namespace Core.Model
{
    [DataContract]
    public  class Device:INotifyPropertyChanged
    {
        private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        [DataMember]
        public string Id { get; set; }
        [DataMember]
        public int Position { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string ChannelId { get; set; }

        private string devTypeid = "";

        //[DataMember]
        public string DeviceTypeId
        {
            get
            {
                if (DeviceType != null)
                {
                    return DeviceType.Id;
                }
                else
                {
                    return devTypeid;
                }
            }
            set
            {
                devTypeid = value;
            }
        }

        //[DataMember]
        public DeviceType DeviceType { get; set; }

        //[DataMember]
        public string Protocol { get; set; }

        [DataMember]
        public bool IsWork { get; set; } = true;

        //[DataMember]
        public int BreakOff { get; set; } = 3; // 

        private int _breakCnt;
        public int BreakCount// 无接收计数
        {
            get => _breakCnt;
            set
            {
                _breakCnt = value;
                if (_breakCnt >= BreakOff)
                {
                    IsConnected = false;
                }
                else
                {
                    IsConnected = true;
                }
            }
        } 
        //[DataMember]
        public ulong Address { get; set; }
        //[DataMember]
        public ByteOrder ByteOrder { get; set; }

        private bool _isConnected = false;

        [DataMember]
        public bool IsConnected
        {
            get => _isConnected;
            set
            {
                if (value != _isConnected)
                {
                    _isConnected = value;
                    Global.DataAccess.PostData(Id, true, _isConnected);
                    try
                    {
                        string chlName = Global.DataAccess.GetChannel(ChannelId)?.Name ?? "";
                        if (_isConnected)
                            Global.DataAccess.AddEvent(EventType.Communication, EventLevel.Information, $"{chlName}{Name}设备恢复连接!");
                        else
                            Global.DataAccess.AddEvent(EventType.Communication, EventLevel.Error, $"{chlName}{Name}设备连接中断!");
                    }
                    catch
                    {
                    }
                    NotifyPropertyChanged("IsConnected");
                }
            }
        }


        public Device()
        {
            Id = IdHelper.GuidToString();
            Name = "新设备";
            Address = 1;
        }

        public Device Clone(string newId,string chlId)
        {
            Device device = new Device();
            device.Id = newId;
            device.Name = Name;
            device.Address = Address;
            device.BreakCount = BreakCount;
            device.BreakOff = BreakOff;
            device.ByteOrder = ByteOrder;
            device.ChannelId = chlId;
            device.DeviceTypeId = DeviceTypeId;
            device.DeviceType = DeviceType;
            device.Protocol = Protocol;
            device.Position = Position;
            return device;
        }
        public BaseDevProtocol GetBaseDevProtocol()
        {
            try
            {
                if (!string.IsNullOrEmpty(this.Protocol))
                {
                    string strPath = Global.DataAccess.GetDevProtocolPath();
                    DirectoryInfo driverPath = new DirectoryInfo(strPath);
                    FileInfo[] files = driverPath.GetFiles();

                    for (int i = 0; i < files.Length; i++)
                    {
                        FileVersionInfo info = FileVersionInfo.GetVersionInfo(files[i].FullName);
                        if (info.ProductName != this.Protocol) continue;
                        if (files[i].Name.Contains(".dll") || files[i].Name.Contains(".DLL"))
                        {
                            string proPath = Path.Combine(strPath, files[i].Name);
                            Assembly asm = Assembly.Load(new AssemblyName() { CodeBase = proPath });
                            foreach (Type extype in asm.GetExportedTypes())
                            {
                                //确定type为类并且继承自(实现)BaseDevProtocol
                                if (extype.IsClass && typeof(BaseDevProtocol).IsAssignableFrom(extype))
                                {
                                   return (BaseDevProtocol)Activator.CreateInstance(extype);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                _log.Error(this.Protocol+"协议加载出错:" + e.Message);
            }
            return null;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
    [DataContract]
    public enum ByteOrder
    {
        /// <summary>
        /// 即大端模式Big-Endian
        /// </summary>
        [EnumMember]
        高位在前 =0,
        /// <summary>
        /// 即小端模式little-endian
        /// </summary>
        [EnumMember]
        低位在前 =1,
        /// <summary>
        /// 与高字节在前相同
        /// </summary>
        [EnumMember]
        高字在前 =2,
        /// <summary>
        /// 一个字内高字节在前，主要针对双字类型
        /// </summary>
        [EnumMember]
        低字在前 =3,
        /// <summary>
        /// 高字在前，但一个字内低字节在前，
        /// </summary>
        [EnumMember]
        三四一二 = 4 
    }
}
